<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
</head>

<body>
  <h1>fqmyysjjd</h1>
  <script>
    function a() {
      console.log(this)
      console.log(arguments)
    }

    const obj = {
      a,
      b() {
        console.log(this)   // 这是 b : function(){}的简写
      }
    }

    obj.a()  // this为obj
    a(); // this是window


    // // apply和call是Function.prototype上的方法，沿着原型链继承可以找到
    // a.apply(obj, [1, 2])  // 第一个参数时与this绑定的值，第二个参数是传入函数的arguments数组，即改变this调用函数
    // a.call(obj, 1, 2)  // 与apply的区别就是传入函数的参数不用写数组，正常写就好了
    // const a_ = a.bind(obj)  // 返回一个新的方法，this绑定到传入的参数
    // a_()

    // 箭头函数没有This Binding，其this就是上一层作用域的this
    (() => {
      console.log(this)
    })()
    // 打印window

    const obj_ = {
      fun() {
        // 箭头函数则没有this指向，this将在上一级作用域寻找
        (() => {
          // 打印obj_
          console.log(this)
        })();

        // 使用function有具体的指向，非严格模式指向window
        (function() {console.log(this)})()
      }
    }

    obj_.fun()
    // 打印obj_

    // 直接作为定时器的回调函数，this指向window
    // 因为此时obj.b这个方法直接作为定时器的异步的回调在其他线程，1秒后放在了宏任务队列里，此后event loop轮询到
    // 才会把其压入调用栈,作为当前的执行上下文,此时,其只充当定时器的回调函数,而不是对象内的某个属性,在上下文中,this指向全局对象
    setTimeout(obj.b, 1000);

    // 不直接，实际上仍然是在回调函数内部调用了obj.b()，因此this指向obj
    setTimeout(() => {
      obj.b()
    }, 2000);
    

    // 定时器, 直接把某个函数,不管是不是对象内的属性,都会指向window
    setInterval(obj.b, 3000)

    // 基于某个元素的事件监听, 只要把某个函数作为回调, this就会该元素, 如果监听window就指向window
    document.querySelector('h1').addEventListener('click', obj.b)
    document.body.addEventListener('click', obj.b)
    window.addEventListener('click', obj.b)



    function a() {
      function b(){
        function c() {
          console.log(this)
        }
        c()
      }
      b()
    }

  </script>
</body>

</html>